﻿using DynamicAuthorization.Sdk.Model;
using DynamicAuthorization.Sdk.Utils;

namespace OA.Infrastructure.Impl;

internal class RoleService : IRoleService
{
    private readonly DbContext _context;

    public RoleService(DbContext context)
    {
        _context = context;
    }

    public async Task<ListResult<Role.QueryModel>> GetListAsync(CancellationToken cancellationToken)
    {
        var result = new ListResult<Role.QueryModel>();

        try
        {
            var data = await _context.Set<Role>()
                .Where(x => !x.Name.StartsWith("temp"))
                .AsNoTracking()
                .ToListAsync(cancellationToken);

            result.Data = data.Select(x => GetQueryModel(x));

            result.Status = OperationalResult.SUCCESS;
        }
        catch (Exception error)
        {
            result.Status = OperationalResult.ERROR;

            result.Message = error.ToString();
        }

        return result;
    }

    public async Task<PageResult<Role.QueryModel>> GetPageAsync(PageParameter input, CancellationToken cancellationToken)
    {
        var result = new PageResult<Role.QueryModel>();

        try
        {
            var data = await _context.Set<Role>()
                .Where(x => !x.Name.StartsWith("temp"))
                .Skip((input.PageNum - 1) * input.PageSize)
                .Take(input.PageSize)
                .AsNoTracking()
                .ToListAsync(cancellationToken);

            result.Data = data.Select(x => GetQueryModel(x)).ToList();

            foreach (var item in result.Data)
            {
                item.ApiPermissions = item.Types.ToApiPermissionInfo();
                item.RoutePermissions = item.ViewRoutes.ToRoutePermissionInfo();
            }

            result.PageNum = input.PageNum;

            result.PageSize = input.PageSize;

            result.Total = _context.Set<Role>().Count();

            result.Status = OperationalResult.SUCCESS;
        }
        catch (Exception error)
        {
            result.Status = OperationalResult.ERROR;

            result.Message = error.ToString();
        }

        return result;
    }

    public async Task<OperationalResult> CreateAsync(Role.CreateModel role, CancellationToken cancellationToken)
    {
        var result = new OperationalResult();

        try
        {
            var entity = new Role
            {
                RoleCode = Guid.NewGuid().ToString().Replace("-", string.Empty),
                Name = role.Name,
                Types = role.ApiPermissions.FromApiPermissionInfo().ToList(),
                ViewRoutes = role.RoutePermissions.ToList(),
            };

            await _context.Set<Role>().AddAsync(entity, cancellationToken);

            var affectedRows = await _context.SaveChangesAsync(cancellationToken);

            result.Status = affectedRows > 0 ? OperationalResult.SUCCESS : OperationalResult.FAILURE;

            result.Message = $"{affectedRows} rows affected.";
        }
        catch (Exception error)
        {
            result.Status = OperationalResult.ERROR;

            result.Message = error.ToString();
        }

        return result;
    }

    public async Task<OperationalResult> UpdateAsync(int id, Role.UpdateModel role, CancellationToken cancellationToken)
    {
        var result = new OperationalResult();

        try
        {
            var entity = await _context.Set<Role>()
                .Where(m => m.Id.Equals(id))
                .FirstOrDefaultAsync(cancellationToken);

            if (entity is null)
            {
                result.Status = OperationalResult.FAILURE;

                result.Message = "0 rows affected.";

                return result;
            }

            entity.Name = role.Name;
            entity.Types = role.ApiPermissions.FromApiPermissionInfo().ToList();
            entity.ViewRoutes = role.RoutePermissions.ToList();

            _context.Set<Role>().Update(entity);

            var affectedRows = await _context.SaveChangesAsync(cancellationToken);

            result.Status = affectedRows > 0 ? OperationalResult.SUCCESS : OperationalResult.FAILURE;

            result.Message = $"{affectedRows} rows affected.";
        }
        catch (Exception error)
        {
            var exists = await _context.Set<Role>().AnyAsync(m => m.Id.Equals(id), cancellationToken);

            if (!exists)
            {
                result.Status = OperationalResult.FAILURE;

                result.Message = "0 rows affected.";
            }
            else
            {
                result.Status = OperationalResult.ERROR;

                result.Message = error.ToString();
            }
        }

        return result;
    }

    public async Task<OperationalResult> DeleteAsync(int id, CancellationToken cancellationToken)
    {
        var result = new OperationalResult();

        try
        {
            var role = await _context.Set<Role>()
                .Include(x => x.OwnUsers).ThenInclude(x => x.Department)
                .Include(x => x.OwnDepartments).ThenInclude(x => x.Leader)
                .Where(m => m.Id.Equals(id))
                .FirstOrDefaultAsync(cancellationToken);

            if (role is null)
            {
                result.Status = OperationalResult.FAILURE;

                result.Message = "0 rows affected.";

                return result;
            }

            _context.Set<Role>().Remove(role);

            var affectedRows = await _context.SaveChangesAsync(cancellationToken);

            result.Status = affectedRows > 0 ? OperationalResult.SUCCESS : OperationalResult.FAILURE;

            result.Message = $"{affectedRows} rows affected.";
        }
        catch (Exception error)
        {
            result.Status = OperationalResult.ERROR;

            result.Message = error.ToString();
        }

        return result;
    }

    public Task<ListResult<ApiPermissionInfo>> GetApiPermisstionsAsync(CancellationToken cancellationToken)
    {
        var result = new ListResult<ApiPermissionInfo>
        {
            Data = PermissionSniffer.GetAllApiPermissions()
        };

        return Task.FromResult(result);
    }

    public Task<ListResult<RoutePermissionInfo>> GetRoutePermissionsAsync(CancellationToken cancellationToken)
    {
        var result = new ListResult<RoutePermissionInfo>
        {
            Data = PermissionSniffer.GetAllRoutePermissions()
        };

        return Task.FromResult(result);
    }

    internal static Role.QueryModel GetQueryModel(Role role)
    {
        return new Role.QueryModel
        {
            Id = role.Id,
            CreatedDate = role.CreatedDate,
            LastModifiedDate = role.LastModifiedDate,
            RoleCode = role.RoleCode,
            Name = role.Name,
            Types = role.Types,
            ViewRoutes = role.ViewRoutes,
            ApiPermissions = role.Types.ToApiPermissionInfo(),
            RoutePermissions = role.ViewRoutes.ToRoutePermissionInfo()
        };
    }
}